#region Header

// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Ivo Kovacka" email="ivok@internet.sk"/>
//     <version>$Revision: 2691 $</version>
// </file>

#endregion Header

namespace ICSharpCode.TextEditor.Document
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;

    /// <summary>
    /// This class is used to store a pair of lineNr and its color
    /// </summary>
    public class CustomLine
    {
        #region Fields

        public Color Color;
        public int EndLineNr;
        public bool ReadOnly;
        public int StartLineNr;

        #endregion Fields

        #region Constructors

        public CustomLine(int lineNr, Color customColor, bool readOnly)
        {
            this.StartLineNr = this.EndLineNr = lineNr;
            this.Color  = customColor;
            this.ReadOnly = readOnly;
        }

        public CustomLine(int startLineNr, int endLineNr, Color customColor, bool readOnly)
        {
            this.StartLineNr = startLineNr;
            this.EndLineNr = endLineNr;
            this.Color  = customColor;
            this.ReadOnly = readOnly;
        }

        #endregion Constructors
    }

    /// <summary>
    /// This class handles the bookmarks for a buffer
    /// </summary>
    public class CustomLineManager : ICustomLineManager
    {
        #region Fields

        List<CustomLine> lines = new List<CustomLine>();

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Creates a new instance of <see cref="CustomLineManager"/>
        /// </summary>
        internal CustomLineManager(LineManager lineTracker)
        {
            lineTracker.LineCountChanged += MoveIndices;
        }

        #endregion Constructors

        #region Events

        /// <remarks>
        /// Is fired before the change
        /// </remarks>
        public event EventHandler BeforeChanged;

        /// <remarks>
        /// Is fired after the change
        /// </remarks>
        public event EventHandler Changed;

        #endregion Events

        #region Properties

        /// <value>
        /// Contains all custom lines 
        /// </value>
        public List<CustomLine> CustomLines
        {
            get {
                return lines;
            }
        }

        #endregion Properties

        #region Methods

        /// <remarks>
        /// Set Custom Line at the line <code>lineNr</code>
        /// </remarks>
        public void AddCustomLine(int lineNr, Color customColor, bool readOnly)
        {
            OnBeforeChanged();
            lines.Add(new CustomLine(lineNr, customColor, readOnly));
            OnChanged();
        }

        /// <remarks>
        /// Add Custom Lines from the line <code>startLineNr</code> to the line <code>endLineNr</code>
        /// </remarks>
        public void AddCustomLine(int startLineNr, int endLineNr, Color customColor, bool readOnly)
        {
            OnBeforeChanged();
            lines.Add(new CustomLine(startLineNr, endLineNr, customColor, readOnly));
            OnChanged();
        }

        /// <remarks>
        /// Clears all custom lines
        /// </remarks>
        public void Clear()
        {
            OnBeforeChanged();
            lines.Clear();
            OnChanged();
        }

        /// <remarks>
        /// Returns the Color if the line <code>lineNr</code> has custom bg color
        /// otherwise returns <code>defaultColor</code>
        /// </remarks>
        public Color GetCustomColor(int lineNr, Color defaultColor)
        {
            foreach(CustomLine line in lines)
                if (line.StartLineNr <= lineNr && line.EndLineNr >= lineNr)
                    return line.Color;
            return defaultColor;
        }

        /// <remarks>
        /// Returns the ReadOnly if the line <code>lineNr</code> is custom 
        /// otherwise returns <code>default</code>
        /// </remarks>
        public bool IsReadOnly(int lineNr, bool defaultReadOnly)
        {
            foreach(CustomLine line in lines)
                if (line.StartLineNr <= lineNr && line.EndLineNr >= lineNr)
                    return line.ReadOnly;
            return defaultReadOnly;
        }

        /// <remarks>
        /// Returns true if <code>selection</code> is read only
        /// </remarks>
        public bool IsReadOnly(ISelection selection, bool defaultReadOnly)
        {
            int startLine = selection.StartPosition.Y;
            int endLine = selection.EndPosition.Y;
            foreach (CustomLine customLine in lines) {
                if (customLine.ReadOnly == false)
                    continue;
                if (startLine < customLine.StartLineNr && endLine < customLine.StartLineNr)
                    continue;
                if (startLine > customLine.EndLineNr && endLine > customLine.EndLineNr)
                    continue;
                return true;
            }
            return defaultReadOnly;
        }

        /// <remarks>
        /// Remove Custom Line at the line <code>lineNr</code>
        /// </remarks>
        public void RemoveCustomLine(int lineNr)
        {
            for (int i = 0; i < lines.Count; ++i) {
                if (((CustomLine)lines[i]).StartLineNr <= lineNr && ((CustomLine)lines[i]).EndLineNr >= lineNr) {
                    OnBeforeChanged();
                    lines.RemoveAt(i);
                    OnChanged();
                    return;
                }
            }
        }

        /// <summary>
        /// This method moves all indices from index upward count lines
        /// (useful for deletion/insertion of text)
        /// </summary>
        void MoveIndices(object sender, LineCountChangeEventArgs e)
        {
            bool changed = false;
            OnBeforeChanged();
            for (int i = 0; i < lines.Count; ++i) {
                int startLineNr = ((CustomLine)lines[i]).StartLineNr;
                int endLineNr = ((CustomLine)lines[i]).EndLineNr;
                if (e.LineStart >= startLineNr && e.LineStart < endLineNr) {
                    changed = true;
                    ((CustomLine)lines[i]).EndLineNr += e.LinesMoved;
                }
                else if (e.LineStart < startLineNr) {
                    ((CustomLine)lines[i]).StartLineNr += e.LinesMoved;
                    ((CustomLine)lines[i]).EndLineNr += e.LinesMoved;
                }
                else {
                }
            /*
                if (e.LinesMoved < 0 && lineNr == e.LineStart) {
                    lines.RemoveAt(i);
                    --i;
                    changed = true;
                } else if (lineNr > e.LineStart + 1 || (e.LinesMoved < 0 && lineNr > e.LineStart))  {
                    changed = true;
                    ((CustomLine)lines[i]).StartLineNr += e.LinesMoved;
                    ((CustomLine)lines[i]).EndLineNr += e.LinesMoved;
                }
            */
            }

            if (changed) {
                OnChanged();
            }
        }

        void OnBeforeChanged()
        {
            if (BeforeChanged != null) {
                BeforeChanged(this, null);
            }
        }

        void OnChanged()
        {
            if (Changed != null) {
                Changed(this, null);
            }
        }

        #endregion Methods
    }
}